package com.vkdasari.youtube;
/* Copyright (c) 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.text.DecimalFormat;

import javax.activation.MimetypesFileTypeMap;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import sample.util.SimpleCommandLineParser;

import com.google.gdata.client.media.ResumableGDataFileUploader;
import com.google.gdata.client.uploader.ProgressListener;
import com.google.gdata.client.uploader.ResumableHttpFileUploader;
import com.google.gdata.client.youtube.YouTubeService;
import com.google.gdata.data.media.MediaFileSource;
import com.google.gdata.data.media.mediarss.MediaCategory;
import com.google.gdata.data.media.mediarss.MediaDescription;
import com.google.gdata.data.media.mediarss.MediaKeywords;
import com.google.gdata.data.media.mediarss.MediaTitle;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.data.youtube.YouTubeMediaGroup;
import com.google.gdata.data.youtube.YouTubeNamespace;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import com.vkdasari.youtube.model.Video;
import com.vkdasari.youtube.ui.model.VideoUploadTableModel;

/**
 * Demonstrates YouTube Data API operation to upload large media files.
 * 
 * 
 */
public class YouTubeUploadClient {

	/**
	 * The URL used to resumable upload
	 */
	public static final String RESUMABLE_UPLOAD_URL = "http://uploads.gdata.youtube.com/resumable/feeds/api/users/default/uploads";

	/** Time interval at which upload task will notify about the progress */
	private static final int PROGRESS_UPDATE_INTERVAL = 1000;

	/** Max size for each upload chunk */
	private static final int DEFAULT_CHUNK_SIZE = 10000000;

	/** Steam to print status messages to. */
	PrintStream output;
	
	private String sourceFolder;
	
	private VideoUploadTableModel tableModel = new VideoUploadTableModel();
	
	private int currentFile = 0;
	
	DecimalFormat df = new DecimalFormat("#.##");

	
	/**
	 * @return the sourceFolder
	 */
	public String getSourceFolder() {
		return sourceFolder;
	}

	/**
	 * @param sourceFolder the sourceFolder to set
	 */
	public void setSourceFolder(String sourceFolder) {
		this.sourceFolder = sourceFolder;
	}

	/**
	 * Input stream for reading user input.
	 */
	private static final BufferedReader bufferedReader = new BufferedReader(
			new InputStreamReader(System.in));

	/**
	 * A {@link ProgressListener} implementation to track upload progress. The
	 * listener can track multiple uploads at the same time.
	 */
	private class FileUploadProgressListener implements ProgressListener {
		public synchronized void progressChanged(
				ResumableHttpFileUploader uploader) {
			switch (uploader.getUploadState()) {
			case COMPLETE:
				output.println("Upload Completed");
				break;
			case CLIENT_ERROR:
				output.println("Upload Failed");
				break;
			case IN_PROGRESS:
				output.println(String.format("%3.0f",
						uploader.getProgress() * 100)
						+ "%");
				break;
			case NOT_STARTED:
				output.println("Upload Not Started");
				break;
			}
		}
	}

	private YouTubeUploadClient(PrintStream out) {
		this.output = out;
	}
	
	private String getSize(long size){
		return String.valueOf(df.format(size/1048576.00))+" mb";
	}
	
	private void displayUploader(){
		
		
		JTable uploadTable = new JTable(tableModel);
		
		JScrollPane scrollPane = new JScrollPane(uploadTable);
		
		JPanel mainPanel = new JPanel(new GridLayout(1,0));
		mainPanel.add(scrollPane);
		//mainPanel.setSize(400, 300);
		
		JFrame mainFrame = new JFrame();
		mainFrame.setTitle("YouTube Client");
		mainFrame.getContentPane().add(mainPanel, BorderLayout.CENTER);
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainFrame.setSize(900, 400);
		mainFrame.setVisible(true);
		
		// Load Files
		File dir = new File(sourceFolder);
		for (File child : dir.listFiles()) {
			if (".".equals(child.getName()) || "..".equals(child.getName())) {
				continue; // Ignore the self and parent aliases.
			}
			Video video = new Video();
			video.setName(child.getName());
			video.setFilelocation(child.getAbsolutePath());
			video.setSize(getSize(child.length()));
			tableModel.addRow(video);
			
		}
		
	}

	private void uploadAll(YouTubeService service) throws Exception {
		displayUploader();
		
		File dir = new File(sourceFolder);
		for (File child : dir.listFiles()) {
			if (".".equals(child.getName()) || "..".equals(child.getName())) {
				continue; // Ignore the self and parent aliases.
			}
			uploadVideo(service, child);
		}
	}

	/**
	 * Uploads a new video to YouTube.
	 * 
	 * @param service
	 *            An authenticated YouTubeService object.
	 * @throws IOException
	 *             Problems reading user input.
	 */
	private void uploadVideo(YouTubeService service, File fileToUpload)
			throws IOException, ServiceException, InterruptedException {

		tableModel.setValueAt("Uploading..", currentFile, 6);
		File videoFile = fileToUpload;
		if (!videoFile.exists()) {
			output.println("Sorry, that video doesn't exist.");
			return;
		}
		System.out.println("Starting Upload.. "
				+ fileToUpload.getAbsolutePath());

		MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();

		// only by file name
		String mimeType = mimeTypesMap.getContentType(videoFile);

		// or by actual File instance
		if (null == mimeType || mimeType.length() < 0) {
			mimeType = mimeTypesMap.getContentType(videoFile);
		}

		MediaFileSource ms = new MediaFileSource(videoFile, mimeType);

		String videoTitle = videoFile.getName();

		VideoEntry newEntry = new VideoEntry();
		YouTubeMediaGroup mg = newEntry.getOrCreateMediaGroup();
		mg.addCategory(new MediaCategory(YouTubeNamespace.CATEGORY_SCHEME,
				"Tech"));
		mg.setTitle(new MediaTitle());
		mg.getTitle().setPlainTextContent(videoTitle);
		mg.setKeywords(new MediaKeywords());
		mg.getKeywords().addKeyword("vijay");
		mg.setDescription(new MediaDescription());
		mg.getDescription().setPlainTextContent(videoTitle);
		mg.setPrivate(true);

		FileUploadProgressListener listener = new FileUploadProgressListener();
		ResumableGDataFileUploader uploader = new ResumableGDataFileUploader.Builder(
				service, new URL(RESUMABLE_UPLOAD_URL), ms, newEntry).title(
				videoTitle).trackProgress(listener, PROGRESS_UPDATE_INTERVAL)
				.chunkSize(DEFAULT_CHUNK_SIZE).build();

		uploader.start();
		while (!uploader.isDone()) {
			Thread.sleep(PROGRESS_UPDATE_INTERVAL);
		}

		String status = "";
		switch (uploader.getUploadState()) {
		case COMPLETE:
			status = "Uploaded successfully";
			output.println(status);
			break;
		case CLIENT_ERROR:
			status = "Upload Failed";
			output.println(status);
			break;
		default:
			status = "Unexpected upload status";
			output.println(status);
			break;
		}
		
		tableModel.setValueAt(status, currentFile, 6);
		currentFile++;
		
	}

	/**
	 * YouTubeUploadClient is a sample command line application that
	 * demonstrates how to upload large media files to youtube. This sample uses
	 * resumable upload feature to upload large media.
	 * 
	 * @param args
	 *            Used to pass the username and password of a test account.
	 */
	public static void main(String[] args) {
		SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
		String sourceFolder = parser.getValue("source", "C:\\Users\\VDasari\\Videos\\Upload");
		String developerKey = "AI39si7rE383yjkPGxq3MUQBDM4QB3W0zGvrFZ7oe6cBr8c5npAf5kvJLV0Ievt7IBaQkza9Ryw5pMCp-qFgN5ZrbJoo5cdPIA";

		if (sourceFolder == null) {
			System.exit(1);
		}

		YouTubeService service = new YouTubeService(
				"VJ-YouTube-Client", developerKey);

		YouTubeUploadClient client = new YouTubeUploadClient(System.out);
		client.setSourceFolder(sourceFolder);
		String[] credits = client.getIDandPassword();

		String username = credits[0];
		String password = credits[1];

		try {
			service.setUserCredentials(username, password);
		} catch (AuthenticationException e) {
			System.out.println("Invalid login credentials.");
			System.exit(1);
		}

		try {
			client.uploadAll(service);

		} catch (IOException e) {
			// Communications error
			System.err
					.println("There was a problem communicating with the service.");
			e.printStackTrace();
		} catch (ServiceException se) {
			System.out.println("Sorry, your upload was invalid:");
			System.out.println(se.getResponseBody());
			se.printStackTrace();
		} catch (InterruptedException ie) {
			System.out.println("Upload interrupted");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//System.exit(0);

	}

	/**
	 * Reads a line of text from the standard input.
	 * 
	 * @throws IOException
	 *             If unable to read a line from the standard input.
	 * @return A line of text read from the standard input.
	 */
	private static String readLine() throws IOException {
		return bufferedReader.readLine();
	}

	/**
	 * Reads a line of text from the standard input and returns the parsed
	 * integer representation.
	 * 
	 * @throws IOException
	 *             If unable to read a line from the standard input.
	 * @return An integer read from the standard input.
	 */
	private static int readInt() throws IOException {
		String input = readLine();

		try {
			return Integer.parseInt(input);
		} catch (NumberFormatException nfe) {
			return 0;
		}

	}

	/**
	 * Prompts for just password Not using this method for now
	 * 
	 * @return Password
	 */
	private String promptPassword() {
		final JPasswordField jpf = new JPasswordField();
		JOptionPane jop = new JOptionPane(jpf, JOptionPane.QUESTION_MESSAGE,
				JOptionPane.OK_CANCEL_OPTION);
		JDialog dialog = jop.createDialog("Password:");
		dialog.addComponentListener(new ComponentAdapter() {

			public void componentShown(ComponentEvent e) {
				SwingUtilities.invokeLater(new Runnable() {

					public void run() {
						jpf.requestFocusInWindow();
					}
				});
			}
		});
		dialog.setVisible(true);
		int result = (Integer) jop.getValue();
		dialog.dispose();
		char[] password = null;
		if (result == JOptionPane.OK_OPTION) {
			password = jpf.getPassword();
		}
		return String.valueOf(password);
	}

	/**
	 * Prompts for both User Name and Password
	 * 
	 * @return
	 */
	private String[] getIDandPassword() {
		JPanel connectionPanel;

		// Create the labels and text fields.
		JLabel userNameLabel = new JLabel("User ID:   ", JLabel.RIGHT);
		JTextField userNameField = new JTextField("", 30);

		JLabel passwordLabel = new JLabel("Password:   ", JLabel.RIGHT);
		JTextField passwordField = new JPasswordField("", 30);

		String[] ConnectOptionNames = { "Login", "Cancel" };

		connectionPanel = new JPanel(false);
		connectionPanel.setLayout(new BoxLayout(connectionPanel,
				BoxLayout.X_AXIS));
		
		JPanel namePanel = new JPanel(false);
		namePanel.setLayout(new GridLayout(0, 1));
		namePanel.add(userNameLabel);
		namePanel.add(passwordLabel);
		
		JPanel fieldPanel = new JPanel(false);
		fieldPanel.setLayout(new GridLayout(0, 1));
		fieldPanel.add(userNameField);
		fieldPanel.add(passwordField);
		
		connectionPanel.add(namePanel);
		connectionPanel.add(fieldPanel);
		
		// Connect or quit
		if (JOptionPane.showOptionDialog(null, connectionPanel,
				"YouTube Credentials", JOptionPane.OK_CANCEL_OPTION,
				JOptionPane.INFORMATION_MESSAGE, null, ConnectOptionNames,
				ConnectOptionNames[0]) != 0) {
			System.exit(0);
		}

		return new String[] { userNameField.getText(), passwordField.getText() };
	}

}
